package com.jiuqian.demo.core.jackson.impl;

import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * 在当前线程内保存ObjectMapper供Jackson2HttpMessageConverter使用
 */
public class ThreadJacksonMixInHolder {
	private static ThreadLocal<ThreadJacksonMixInHolder> holderThreadLocal = new ThreadLocal<ThreadJacksonMixInHolder>();
	private Set<Map.Entry<Class<?>, Class<?>>> mixIns;
	private ObjectMapper mapper;
	private org.codehaus.jackson.map.ObjectMapper codehausMapper;

	/**
	 * 根据当前MixIn集合生成objectMapper
	 * <p>
	 * <p/>
	 * <b>注意：该方法在返回mapper对象之后调用clear方法，如果再次调用builderMapper()肯定会保存</b>
	 *
	 * @return
	 */
	public static ObjectMapper builderMapper() {
		ThreadJacksonMixInHolder holder = holderThreadLocal.get();
		if (holder.mapper == null && isContainsMixIn()) {
			holder.mapper = new ObjectMapper();
			// holder.mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
			for (Map.Entry<Class<?>, Class<?>> mixIn : holder.mixIns) {
				holder.mapper.addMixIn(mixIn.getKey(), mixIn.getValue());
			}
		}
		clear();// 如果不调用clear可能导致线程内的数据是脏的！
		return holder.mapper;
	}

	/**
	 * 根据当前MixIn集合生成objectMapper
	 *
	 * @return
	 */
	public static org.codehaus.jackson.map.ObjectMapper builderCodehausMapper() {
		ThreadJacksonMixInHolder holder = holderThreadLocal.get();
		if (holder.codehausMapper == null && isContainsMixIn()) {
			holder.codehausMapper = new org.codehaus.jackson.map.ObjectMapper();
			for (Map.Entry<Class<?>, Class<?>> mixIn : holder.mixIns) {
				holder.codehausMapper.getDeserializationConfig().addMixInAnnotations(mixIn.getKey(), mixIn.getValue());
				holder.codehausMapper.getSerializationConfig().addMixInAnnotations(mixIn.getKey(), mixIn.getValue());
			}
		}
		clear();// 如果不调用clear可能导致线程内的数据是脏的！
		return holder.codehausMapper;
	}

	/**
	 * 清除当前线程内的数据
	 */
	public static void clear() {
		holderThreadLocal.set(null);
		// holderThreadLocal.remove();
	}

	/**
	 * 设置MixIn集合到线程内，如果线程内已经存在数据，则会先清除
	 *
	 * @param resetMixIns
	 */
	public static void setMixIns(Set<Map.Entry<Class<?>, Class<?>>> resetMixIns) {
		ThreadJacksonMixInHolder holder = holderThreadLocal.get();
		if (holder == null) {
			holder = new ThreadJacksonMixInHolder();
			holderThreadLocal.set(holder);
		}
		holder.mixIns = resetMixIns;
	}

	/**
	 * 不同于setMixIns，addMixIns为增加MixIn集合到线程内，即不会清除已经保存的数据 <br>
	 * 2014年4月4日 下午12:08:15
	 *
	 * @param toAddMixIns
	 */
	public static void addMixIns(Set<Map.Entry<Class<?>, Class<?>>> toAddMixIns) {
		ThreadJacksonMixInHolder holder = holderThreadLocal.get();
		if (holder == null) {
			holder = new ThreadJacksonMixInHolder();
			holderThreadLocal.set(holder);
		}
		if (holder.mixIns == null) {
			holder.mixIns = new HashSet<Map.Entry<Class<?>, Class<?>>>();
		}
		holder.mixIns.addAll(toAddMixIns);
	}

	/**
	 * 获取线程内的MixIn集合
	 * <p>
	 * </p>
	 * <b>注意：为了防止线程执行完毕之后仍然存在有数据，请务必适时调用clear()方法</b>
	 *
	 * @return
	 * @see com.xiongyingqi.jackson.helper.ThreadJacksonMixInHolder#builderMapper()
	 * @see com.xiongyingqi.jackson.helper.ThreadJacksonMixInHolder#builderCodehausMapper()
	 * @see com.xiongyingqi.jackson.helper.ThreadJacksonMixInHolder#clear()
	 */
	public static Set<Map.Entry<Class<?>, Class<?>>> getMixIns() {
		ThreadJacksonMixInHolder holder = holderThreadLocal.get();
		return holder.mixIns;
	}

	/**
	 * 判断当前线程是否存在MixIn集合
	 *
	 * @return
	 */
	public static boolean isContainsMixIn() {
		if (holderThreadLocal.get() == null) {
			return false;
		}
		if (holderThreadLocal.get().mixIns != null && holderThreadLocal.get().mixIns.size() > 0) {
			return true;
		}
		return false;
	}

}
